package com.ricky.mq.client.code.handler;

import com.ricky.mq.client.connection.ClientConnection;
import com.ricky.mq.client.message.data.BaseData;
import com.ricky.mq.client.message.data.CallbackData;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 等待/发送消息处理器
 *
 * @author ricky
 * @since 2020.06.18
 */
public class WaitOrSendMsgHandler {
    /**
     * 等待消息的map
     */
    private static Map<String, CallbackData> waitMap = new ConcurrentHashMap<>(16);
    /**
     * 等待超时时间
     */
    private static long WAIT_TIME_OUT = ClientConnection.getClientConnection().getWaitTimeOut();

    /**
     * 同步发送消息至服务器
     *
     * @param commandCode 命令码
     * @param baseData    数据体
     * @return CallbackData 同步返回结果
     */
    public static CallbackData syncSendData(String commandCode, BaseData baseData) {
        try {
            waitMap.put(baseData.getUuid(), CallbackData.build());
            if (ClientConnection.getClientConnection().sendData(commandCode, baseData)) {
                return sync(baseData.getUuid());
            }
            return waitMap.get(baseData.getUuid()).setSuccess(false);
        } catch (Exception e) {
            return waitMap.get(baseData.getUuid()).setSuccess(false);
        } finally {
            waitMap.remove(baseData.getUuid());
        }
    }

    /**
     * 异步发送消息至服务器
     *
     * @param commandCode 命令码
     * @param baseData    数据体
     * @return 同步返回结果
     */
    public static CallbackData asyncSendData(String commandCode, BaseData baseData) {
        try {
            waitMap.put(baseData.getUuid(), CallbackData.build());
            if (ClientConnection.getClientConnection().sendData(commandCode, baseData)) {
                return async(baseData.getUuid());
            }
            return waitMap.get(baseData.getUuid()).setSuccess(false);
        } catch (Exception e) {
            return waitMap.get(baseData.getUuid()).setSuccess(false);
        } finally {
            waitMap.remove(baseData.getUuid());
        }
    }

    /**
     * 异步等待
     *
     * @param uuid 消息唯一标识
     * @return CallbackData 结果
     * @throws Exception
     */
    private static CallbackData async(String uuid) throws Exception {
        return waitMap.get(uuid).setSuccess(true);
    }

    /**
     * 同步等待
     *
     * @param uuid 消息唯一标识
     * @return CallbackData 结果
     * @throws Exception
     */
    private static CallbackData sync(String uuid) throws Exception {
        try {
            // 同步间隔值
            int sleepTime = 100;
            while (true) {
                CallbackData callbackData = waitMap.get(uuid);
                if (callbackData.isSuccess()) {
                    return callbackData;
                }

                if (System.currentTimeMillis() - callbackData.getSendTimeMillis() > WAIT_TIME_OUT) {
                    return callbackData;
                }
                Thread.sleep(sleepTime);
            }
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    /**
     * 设置服务端返回数据
     *
     * @param baseData 服务端返回数据
     */
    public static void setCallbackData(BaseData baseData) {
        if (waitMap.containsKey(baseData.getUuid())) {
            waitMap.put(baseData.getUuid(), CallbackData.build().setSuccess(true).setBaseData(baseData));
        }
    }
}
